package com.example.springboot.filter;

import com.example.springboot.constant.ConstantKey;
import com.example.springboot.service.GrantedAuthorityImpl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.thymeleaf.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String authorization = request.getHeader("Authorization");
        if (StringUtils.isEmpty(authorization) || !authorization.startsWith("Basic ")) {
            chain.doFilter(request,response);
            return;
        }
        UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(request,response);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        chain.doFilter(request,response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request,HttpServletResponse response)
        throws ServletException,IOException {
        long currentTime = System.currentTimeMillis();
        String token = request.getHeader("Authorization");
        String user = null;
        Claims claims = Jwts.parser().setSigningKey(ConstantKey.SIGNING_KEY)
                .parseClaimsJws(token.replace("Basic ","")).getBody();
        long issueTime = claims.getIssuedAt().getTime();
        long nowTime = System.currentTimeMillis();
        long expirationTime = claims.getExpiration().getTime();

        if ( (issueTime + ( expirationTime - issueTime ) / 2) < currentTime && currentTime < expirationTime  ) {
            Calendar calendar = Calendar.getInstance();
            Date issue = calendar.getTime();
            calendar.setTime(new Date());
            calendar.add(Calendar.MINUTE,5);
            Date expiration = calendar.getTime();
            String refreshToken = Jwts.builder().setSubject(claims.getSubject())
                    .setIssuedAt(issue)
                    .setExpiration(expiration)
                    .signWith(SignatureAlgorithm.HS512, ConstantKey.SIGNING_KEY)
                    .compact();
            response.addHeader("Authorization",refreshToken);
        }
        long now = System.currentTimeMillis();
        user = claims.getSubject();
        if (user != null) {
            String[] split = user.split("-")[1].split(",");
            List<GrantedAuthority> authorityList = new ArrayList<>();
            for(int i=0;i<split.length;i++) {
                authorityList.add(new GrantedAuthorityImpl(split[i]));
            }
            return new UsernamePasswordAuthenticationToken(user,null,authorityList);
        }
        return null;
    }
}
